/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_fibers_interpret_Interpret
#define simodo_fibers_interpret_Interpret

/*! \file Interpret.h
    \brief Реализация волокна интерпретации абстрактного дерева операционной семантики
*/

#include "simodo/interpret/Interpret_interface.h"
#include "simodo/loom/Fiber_interface.h"
#include "simodo/loom/Loom_interface.h"
#include "simodo/interpret/SemanticModuleFactory_interface.h"

#include "simodo/interpret/StackOfNames.h"
#include "simodo/inout/reporter/Reporter_abstract.h"
#include "simodo/ast/Node.h"

#include <vector>
#include <iterator>
#include <functional>

namespace simodo::interpret
{
    typedef std::vector<std::shared_ptr<SemanticModuleFactory_interface>> SemanticFactories;

    /**
     * @brief Реализация волокна интерпретации абстрактного дерева операционной семантики.
     * 
     */
    class Interpret :   public loom::Fiber_interface,
                        public Interpret_interface,
                        /// \todo Желательно выделить в отдельные классы реализации
                        public ExpressionPrimitives_interface,
                        public Parallelize_interface
    {
        InterpretType                   _type;
        inout::Reporter_abstract &      _m;         ///< Обработчик сообщений
        loom::Loom_interface &          _loom;      ///< Система исполнения SIMODO loom
        inout::uri_set_t                _files;     ///< Файлы исходного кода, участвующие в интерпретации (необходимы для диагностики и отладки)
        SemanticFactories               _semantic_factories;    ///< Фабрики семантических модулей

        SemanticModules                 _hosts;         ///< Перечень обработчиков семантических правил
        std::vector<FlowLayerInfo>      _layer_stack;   ///< Стек прохода абстрактного дерева операционной семантики

        StackOfNames                    _stack;

        std::u16string                  _last_host_name = u"***";
        SemanticModule_interface *      _last_host      = nullptr;
        bool                            _errors = false;
        bool                            _stop_by_error = false;

        variable::Value                 _return_value;

        std::vector<ChildFlowInfo>      _childs;
        const loom::Fiber_interface *   _waiting_for = nullptr;

        std::vector<BreakPoint>         _breakpoints;

    public:
        Interpret() = delete;

        /**
         * @brief Конструктор интерпретатора на основе абстрактного дерева операционной семантики.
         * 
         * @param type  Тип интерпретации
         * @param m     Ссылка на получателя сообщений 
         * @param loom  Ссылка на ткацкий станок
         * @param files Файлы, на которых построено дерево операционной семантики code 
         * @param code  Ссылка на абстрактное дерево операционной семантики
         * @param hosts Перечень обработчиков семантических правил 
         * @param stop_by_error  Запрос остановку при возникновении runtime-ошибок
         */
        Interpret(
                InterpretType type,
                inout::Reporter_abstract & m, 
                loom::Loom_interface & loom, 
                inout::uri_set_t files, 
                const ast::Node & code,
                interpret::SemanticModules hosts = {},
                bool stop_by_error=false);

        /**
         * @brief Конструктор волокна на основе абстрактного дерева операционной семантики.
         * 
         * @param type  Тип интерпретации
         * @param m     Ссылка на получателя сообщений 
         * @param loom  Ссылка на ткацкий станок
         * @param semantic_factories Перечень фабрик обработчиков семантических правил 
         * @param stop_by_error  Запрос остановку при возникновении runtime-ошибок
         */
        Interpret(
                InterpretType type,
                inout::Reporter_abstract & m, 
                loom::Loom_interface & loom, 
                SemanticFactories semantic_factories,
                bool stop_by_error=false);

        /**
         * @brief Destroy the Interpret object
         * 
         */
        ~Interpret();

    // loom::Fiber_interface
    public:
        virtual loom::FiberStatus       start()                                   override;
        virtual loom::FiberStatus       tieKnot()                                 override;
        virtual void                    finish()                                  override;
        virtual bool                    isReady()                           const override; 
        virtual const loom::Fiber_interface * getWaitingFor()                     override;

    // Interpret_interface
    public:
        virtual loom::Fiber_interface * fiber()                                   override { return this; }
        virtual StackOfNames_interface &stack()                                   override { return _stack; }
        virtual ExpressionPrimitives_interface &expr()                            override { return *this; }
        virtual Parallelize_interface & parallelize()                             override { return *this; }

        virtual void instantiateSemantics(interpret::SemanticModules hosts)       override;

        virtual const inout::uri_set_t & files()                            const override { return _files; }
        virtual inout::Reporter_abstract & reporter()                       const override { return _m; }
        virtual bool                    errors()                            const override { return _errors; }
        virtual void                    setStopByError(bool stop_by_error = true) override { _stop_by_error = stop_by_error; }
        virtual const FlowLayerInfo &   flow()                              const override { return _layer_stack.back(); }
        virtual InterpretType           type()                              const override { return _type; }

        virtual void                    setErrorSign(bool error_sign=true) override { _layer_stack.back().error_sign = error_sign; }
        virtual void                    addFile(const std::string & path_to_file) override;

        virtual void                    addFlowLayer(const ast::Node & code, 
                                                    boundary_index_t boundary_index, 
                                                    std::function<void (const FlowLayerInfo &)> on_layer_end = nullptr) override;
        virtual bool                    flushLayers(const ast::Node & code, bool invoke_callback) override;

        virtual bool                    execute(const ast::Node & code)           override;
        virtual loom::FiberStatus       executeOperation()                        override;
        virtual const ast::Node *       lookupOperationNode(int shift=0,
                                                            boundary_index_t bound=UNDEFINED_BOUNDARY_INDEX) const override;

        virtual boundary_index_t        copyBaseBounds(const StackOfNames_interface & other) override;

        virtual loom::Loom_interface *  loom()                                    override { return &_loom; }
        virtual void                    addBreakPoints(const std::vector<BreakPoint> & breakpoints) override;
        virtual std::vector<BreakPoint> breakpoints()                       const override;

    // ExpressionPrimitives_interface
    private:
        virtual const variable::Value & return_value() const override { return _return_value; }
        virtual void                    setReturnValue(const variable::Value & value) override { _return_value = value; }

        virtual void                    assignVariable(variable::Variable & lvalue_origin, 
                                                const variable::Variable & rvalue_origin,
                                                bool need_copy = false) override;
        virtual void                    assignArray(variable::Variable & lvalue_origin, 
                                                const variable::Variable & rvalue_origin,
                                                bool need_copy) override;
        virtual void                    assignObject(variable::Variable & lvalue_origin, 
                                                const variable::Variable & rvalue_origin,
                                                bool need_copy) override;
        virtual variable::Variable      convertVariable(const variable::Variable & var, 
                                                variable::ValueType type,
                                                bool need_copy = false) const override;

        virtual std::shared_ptr<variable::Object> self() override;
        virtual std::shared_ptr<variable::Object> makeSelf() override;
        virtual void                    callPreparedFunction(
                                                Interpret_interface * inter,
                                                boundary_index_t boundary_index, 
                                                Notification_interface & visitor,
                                                bool invoke)      override;
        virtual void                    callPreparedFunction(
                                                boundary_index_t boundary_index, 
                                                Notification_interface & visitor,
                                                bool invoke,
                                                const std::function<void(const FlowLayerInfo &)> callback) override;

        virtual void                    print(bool need_detailed_report) const override;
        /// \todo Метод дублирует функцию из variable!
        virtual std::u16string          toString(const variable::Value & value, 
                                                bool need_whole_info=false, 
                                                bool quote_strings=false) const override;

    // Parallelize_interface
    private:
        virtual bool                    addChildFiber(const variable::Variable & var) override;
        virtual bool                    wait(const variable::Variable & var)    override;
        virtual bool                    push(const variable::Variable & var)    override;
        virtual bool                    pull(variable::Variable & var)          override;

        virtual const ChildFlowInfo *   findChildFlowInfo(const variable::Variable & var) const override;

    public:
        static std::u16string   makeOperatorString(const ast::Node & operation_node);

    protected:
        bool                    checkBreakPoint(const ast::Node & node);

        void                    addFlowLayer_internal(const ast::Node & code, 
                                                    boundary_index_t boundary_index, 
                                                    std::function<void (const FlowLayerInfo &)> on_layer_end = nullptr);
    };

}

#endif // simodo_fibers_interpret_Interpret
